﻿using System;
using System.Diagnostics;
using SSM.BusinessLayer.Enums;

namespace SSM.BusinessLayer.Monitors
{
	public class PerfMonitor : BaseMonitor
	{
		#region Constants

		private const String TOTAL_INSTANCE = "_Total";

		#endregion

        #region Properties

		public PerformanceCounter PCounter { get; set; }

		public PerfMonitorType Type
		{
			get
			{
				return GetMonitorType();
			}
		}

		#endregion

		#region Constructor

		public PerfMonitor(PerfMonitorType monitorType)
		{
			Start(String.Empty, String.Empty, TOTAL_INSTANCE, null);
            SetPerformanceCounterType(monitorType);

			ValidateInstance();
		}

		public PerfMonitor(PerfMonitorType monitorType, String instanceName)
		{
			Start(String.Empty, String.Empty, instanceName, null);
            SetPerformanceCounterType(monitorType);

			ValidateInstance();
		}

		public PerfMonitor(PerfMonitorType monitorType, String instanceName, Object objTag)
		{
			Start(String.Empty, String.Empty, instanceName, objTag);
            SetPerformanceCounterType(monitorType);

			ValidateInstance();
		}

		public PerfMonitor(String categoryName, String counterName, String instanceName)
		{
			Start(categoryName, counterName, instanceName, null);
			
			ValidateInstance();
		}

		public PerfMonitor(String categoryName, String counterName, String instanceName, Object objTag)
		{
			Start(categoryName, counterName, instanceName, objTag);
			
			ValidateInstance();
		}

		private void Start(String categoryName, String counterName, String instanceName, Object objTag)
		{
			PCounter = new PerformanceCounter();
			PCounter.InstanceName = instanceName;
			PCounter.CategoryName = categoryName;
			PCounter.CounterName = counterName;
            
			Tag = objTag;
		}

		private void ValidateInstance()
		{
			if (!PerformanceCounterCategory.InstanceExists(PCounter.InstanceName, PCounter.CategoryName))
			{
				if (PCounter.InstanceName == TOTAL_INSTANCE)
				{
					PCounter.InstanceName = String.Empty;
				}
			}
		}

		#endregion

		#region Override BaseMonitor

		public override Single GetNextValue()
		{
			LastValue = PCounter.NextValue();
			LastCheck = DateTime.Now;

			return LastValue;
		}

		public override String Title
		{
			get { return Type.ToString(); }
		}

		#endregion

		#region Set performance counter monitor type

		private void SetPerformanceCounterType(PerfMonitorType type)
		{
			switch (type)
			{
				case PerfMonitorType.CpuLoad:
					PCounter.CategoryName = "Processor";
					PCounter.CounterName = "% Processor Time";
					break;
				case PerfMonitorType.MemoryUsage:
					PCounter.CategoryName = "Memory";
					PCounter.CounterName = "% Committed Bytes In Use";
					break;
				case PerfMonitorType.DiskFreeSpace:
					PCounter.CategoryName = "LogicalDisk";
					PCounter.CounterName = "% Free Space";
					break;
				case PerfMonitorType.DiskLoadTotal:
					PCounter.CategoryName = "LogicalDisk";
					PCounter.CounterName = "% Disk Time";
					break;
				case PerfMonitorType.DiskLoadRead:
					PCounter.CategoryName = "LogicalDisk";
					PCounter.CounterName = "% Disk Read Time";
					break;
				case PerfMonitorType.DiskLoadWrite:
					PCounter.CategoryName = "LogicalDisk";
					PCounter.CounterName = "% Disk Write Time";
					break;
				case PerfMonitorType.NetworkBytesPerSecTotal:
					PCounter.CategoryName = "Network Interface";
					PCounter.CounterName = "Bytes Total/sec";
					break;
				case PerfMonitorType.NetworkBytesPerSecSent:
					PCounter.CategoryName = "Network Interface";
					PCounter.CounterName = "Bytes Sent/sec";
					break;
				case PerfMonitorType.NetworkBytesPerSecReceived:
					PCounter.CategoryName = "Network Interface";
					PCounter.CounterName = "Bytes Received/sec";
					break;
				case PerfMonitorType.TcpConnectionsEstablished:
					PCounter.CategoryName = PerformanceCounterCategory.Exists("TCPv4") ? "TCPv4" : "TCP";
					PCounter.CounterName = "Connections Established";
					break;
			}
		}

		private PerfMonitorType GetMonitorType()
		{
			String category = PCounter.CategoryName.ToLower();
			String counter = PCounter.CounterName.ToLower();

			if (category == "processor")
			{
				if (counter == "% processor time") return PerfMonitorType.CpuLoad;
               
				return PerfMonitorType.Cpu;
			}

			if (category == "memory")
			{
				if (counter == "% committed bytes in use") return PerfMonitorType.MemoryUsage;
				
				return PerfMonitorType.Memory;
			}

			if (category == "logicaldisk")
			{
				if (counter == "% disk time") return PerfMonitorType.DiskLoadTotal;
				if (counter == "% disk read time") return PerfMonitorType.DiskLoadRead;
				if (counter == "% disk write time") return PerfMonitorType.DiskLoadWrite;

				return PerfMonitorType.Disk;
			}

			if (category == "physicaldisk")
			{
				return PerfMonitorType.Disk;
			}

			if (category == "network interface")
			{
				if (counter == "bytes total/sec") return PerfMonitorType.NetworkBytesPerSecTotal;
				if (counter == "bytes sent/sec") return PerfMonitorType.NetworkBytesPerSecSent;
				if (counter == "bytes received/sec") return PerfMonitorType.NetworkBytesPerSecReceived;

				return PerfMonitorType.Network;
			}

			if (category == "tcpv4" || category == "tcp")
			{
				if (counter == "connections established") return PerfMonitorType.TcpConnectionsEstablished;

				return PerfMonitorType.Tcp;
			}

			return PerfMonitorType.Generic;
		}

		#endregion
	}
}